%{
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma       error_messages(off, E_STATEMENT_NOT_REACHED)

/*
 * poolcfg.l
 *
 * Overview
 * poolcfg.l implements a lexer for the poolcfg(1) utility.The lexer uses
 * the token definitions generated by YACC in the file poolcfg_Grammar.h.
 * To make token recognition simpler, the lexer uses a separate state for
 * each of the different data types supported by poolcfg(1).
 *
 * States
 * Lex provides the ability to minimise conflict between qualifying regexps
 * by providing states. A regexp that is qualified by a state will only be
 * used when the state is entered (using the BEGIN <state> command). (The
 * exception to this rule, is that rules defined in the default state are
 * available in all states.)
 *
 * poolcfg.l makes use of type states, one for each of the poolcfg(1)
 * supported data types:
 *
 * ISTATE => int64_t
 * USTATE => uint64_t
 * BSTATE => uchar_t
 * SSTATE => const char *
 * DSTATE => double
 *
 * and a further state, CPUSTATE, to indicate the difference between matching
 * a valid "name" (i.e. id) for a cpu and a valid name for other components of
 * libpool.
 *
 * When a token indicating a variable declaration is matched, the corresponding
 * state is saved in the state variable. Once the assignment ('=') token is
 * matched, the stored state is entered and the additional state specific
 * matching regular expressions become available. Once a state specific
 * token is matched, the default state is restored.
 *
 */
#include <stdlib.h>
#include <sys/types.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <libintl.h>

#include <pool.h>
#include "utils.h"
#include "poolcfg.h"
#include "poolcfg_grammar.h"

static int lex_lineno = 1;		/* line-number for error reporting */
static int state = INITIAL;		/* state to be used */
extern void yyerror(char *s);
extern int dofile;			/* are we processing a file? */
%}

%s ISTATE
%s USTATE
%s BSTATE
%s SSTATE
%s DSTATE
%s CPUSTATE

%%

\n			lex_lineno++;

[ \t]+			;

#.*			;

info			{ return PCC_INFO; }

create			{ return PCC_CREATE; }

destroy			{ return PCC_DESTROY; }

modify			{ return PCC_MODIFY; }

associate		{ return PCC_ASSOC; }

transfer		{
				BEGIN USTATE;
				return PCC_TRANSFER;
			}

discover		{ return PCC_DISC; }

rename			{ return PCC_RENAME; }

to			{ return PCK_TO; }

from			{ return PCK_FROM; }

int			{
				state=ISTATE;
				return PCT_INT;
			}

uint			{
				state=USTATE;
				return PCT_UINT;
			}

boolean			{
				state=BSTATE;
				return PCT_BOOLEAN;
			}

string			{
				state=SSTATE;
				return PCT_STRING;
			}

float			{
				state=DSTATE;
				return PCT_FLOAT;
			}

cpu			{
				BEGIN CPUSTATE;
				return PCE_CPU;
			}

pset			{ return PCE_PSET; }

pool			{ return PCE_POOL; }

system			{ return PCE_SYSTEM; }

\(			{ return PCK_OPENLST; }

\)			{ return PCK_CLOSELST; }

=			{
   				 BEGIN state;
				 return PCK_ASSIGN;
			}

\;			{ return PCK_SEPLST; }

~			{ return PCK_UNDEF; }

<ISTATE>-?[0-9]+	{
				yylval.ival = strtoll(yytext, NULL, 0);
				if (errno == EINVAL || errno == ERANGE) {
					yyerror(gettext("Invalid value"));
					exit(E_ERROR);
				}
				BEGIN INITIAL;
				return PCV_VAL_INT;
			}

<USTATE>[0-9]+		{
				yylval.uval = strtoull(yytext, NULL, 0);
				if (errno == EINVAL || errno == ERANGE) {
					yyerror(gettext("Invalid value"));
					exit(E_ERROR);
				}
				BEGIN INITIAL;
				return PCV_VAL_UINT;
			}


<BSTATE>true|false	{
				if (strcmp(yytext, "true") == 0)
					yylval.bval = 1;
				else
					yylval.bval = 0;
				BEGIN INITIAL;
				return PCV_VAL_BOOLEAN;
			}

<SSTATE>\"[^\"\n]*[\"\n] {
				if((yylval.sval = strdup(yytext+1)) == NULL) {
					yyerror(gettext("Out of memory"));
					exit(E_ERROR);
				}
				if (yylval.sval[yyleng-2] =='"')
					yylval.sval[yyleng-2] = 0;
				BEGIN INITIAL;
				return PCV_VAL_STRING;
			}

<DSTATE>([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) {
				yylval.dval = strtod(yytext, (char **)NULL);
				if (errno == EINVAL || errno == ERANGE) {
					yyerror(gettext("Invalid value"));
					exit(E_ERROR);
				}
				BEGIN INITIAL;
				return PCV_VAL_FLOAT;
			}

[A-Za-z][A-Za-z0-9,._-]*	{
				if ((yylval.sval = strdup(yytext)) == NULL) {
					yyerror(gettext("Out of memory"));
					exit(E_ERROR);
				}
 				return PCV_SYMBOL;
			}

<CPUSTATE>[0-9]+	{
				if ((yylval.sval = strdup(yytext)) == NULL) {
					yyerror(gettext("Out of memory"));
					exit(E_ERROR);
				}
				BEGIN INITIAL;
 				return PCV_SYMBOL;
			}
.			{
				yyerror(gettext("Illegal character"));
				exit(E_ERROR);
			}

%%

void
yyerror(char *s)
{
	if (dofile == PO_TRUE) {
		if (yytext[0] == '\0') {
			(void) warn(gettext("line %d, %s, token expected\n"),
			    lex_lineno, s);
			return;
		}
		(void) warn(gettext("line %d, %s at '%s'\n"), lex_lineno, s,
		    yytext);
	} else {
		if (yytext[0] == '\0') {
			(void) warn(gettext("%s, token expected\n"), s);
			return;
		}
		(void) warn(gettext("%s at '%s'\n"), s, yytext);
	}
}

